home *** CD-ROM | disk | FTP | other *** search
/ SGI Hot Mix 17 / Hot Mix 17.iso / HM17_SGI / research / lib / cw_zoom.pro < prev    next >
Text File  |  1997-07-08  |  14KB  |  458 lines

  1. ; $Id: cw_zoom.pro,v 1.10 1997/02/25 23:40:54 lubos Exp $
  2. ;
  3. ; Copyright (c) 1992-1997, Research Systems, Inc.  All rights reserved.
  4. ;    Unauthorized reproduction prohibited.
  5. ;+
  6. ; NAME:
  7. ;    CW_ZOOM
  8. ;
  9. ; PURPOSE:
  10. ;    This compound widget displays two images: an original image
  11. ;    in one window and a portion of the original image in another.
  12. ;    The user may select the center of the zoom region, the zoom scale,
  13. ;    the interpolation style, and the method of indicating the zoom center.
  14. ;
  15. ; CATEGORY:
  16. ;    Compound widgets.
  17. ;
  18. ; CALLING SEQUENCE:
  19. ;    Widget = CW_ZOOM(Parent)
  20. ;
  21. ; INPUTS:
  22. ;       Parent:     The ID of the parent widget.
  23. ;
  24. ; KEYWORD PARAMETERS:
  25. ;    FRAME:     If set, a frame will be drawn around the widget. The
  26. ;         default is FRAME=0 (no frame).
  27. ;    MAX:     The maximum zoom scale, which must be greater than
  28. ;         or equal to 1. The default = 20.
  29. ;    MIN:     The minimum zoom scale, which must be greater than
  30. ;         or equal to 1. The default = 1.
  31. ;    RETAIN:     Controls the setting for backing store for both windows.
  32. ;         If backing store is provided, a window which was obscured
  33. ;         will be redrawn when it becomes exposed. Set RETAIN=0 for
  34. ;         no backing store. Set RETAIN=1 to "request backing store
  35. ;         from server" (this is the default). Set RETAIN=2 for IDL
  36. ;         to provide backing store.
  37. ;    SAMPLE:     Set to zero for bilinear interpolation, or to a non-zero
  38. ;         value for nearest neighbor interpolation. Bilinear
  39. ;         interpolation gives higher quality results, but requires
  40. ;         more time. The default is SAMPLE=0 (bilinear interpolation).
  41. ;    SCALE:     The initial integer scale factor to use for the zoomed image.
  42. ;         The default is SCALE=4. The scale must be greater than or
  43. ;         equal to 1.
  44. ;    TRACK:     Set to zero if the zoom window should be updated only when
  45. ;         the mouse button is pressed. Set to a non-zero value if the
  46. ;         zoom window should be updated continuously as the cursor
  47. ;         is moved across the original image. Note: On slow systems,
  48. ;         /TRACK performance can be inadequate. The default is TRACK=0.
  49. ;    UVALUE:     The user value for the widget.
  50. ;    XSIZE:     The width of the window (in pixels) for the original image.
  51. ;         The default is 500.
  52. ;    YSIZE:     The height of the window (in pixels) for the original image.
  53. ;         The default is 500.
  54. ;    X_SCROLL_SIZE: The width of the visible part of the original image.
  55. ;               This may be smaller than the actual width controlled
  56. ;               by the XSIZE keyword. The default is 0, for no
  57. ;               scroll bar.
  58. ;    Y_SCROLL_SIZE: The height of the visible part of the original image.
  59. ;               This may be smaller than the actual height controlled
  60. ;               by the YSIZE keyword. The default is 0, for no
  61. ;               scroll bar.
  62. ;    X_ZSIZE: The width of the window for the zoomed image.
  63. ;         The default is 250.
  64. ;    Y_ZSIZE: The height of the window for the zoomed image.
  65. ;         The default is 250.
  66. ;
  67. ; OUTPUTS:
  68. ;       The ID of the created widget is returned.
  69. ;
  70. ; SIDE EFFECTS:
  71. ;    When the "Report Zoom to Parent" button is pressed, this widget
  72. ;    will generate an event structure containing several data fields.
  73. ;        x_zsize, y_zsize:    size of the zoomed image
  74. ;        x0, y0:            lower left corner in original image
  75. ;        x1, y1:            upper right corner in original image
  76. ;    This event is a report to the parent that allows retrieval of the
  77. ;    zoomed image using WIDGET_CONTROL.
  78. ;
  79. ; PROCEDURE:
  80. ;    WIDGET_CONTROL, id, SET_VALUE=value can be used to change the
  81. ;        original, unzoomed image displayed by the widget.
  82. ;        The value may not be set until the widget has been
  83. ;        realized.
  84. ;
  85. ;    WIDGET_CONTROL, id, GET_VALUE=var can be used to obtain the current
  86. ;        zoomed image displayed by the widget.
  87. ;
  88. ; MODIFICATION HISTORY:
  89. ;    June 30, 1992, ACY
  90. ;       7 April 1993, AB, Removed state caching.
  91. ;    13 June, 1994, ACY, Save window and set to zoom prior to erase
  92. ;                Add byte conversion in set_value
  93. ;    23 November, 1994, ACY, add code to handle cases in which the
  94. ;            set_value image is larger or smaller than the
  95. ;            original image.  Also remove scaling on display
  96. ;            operation (only scale the image when it is set.)
  97. ;-
  98.  
  99. ;-----------------------------------------------------------------------------
  100.  
  101. PRO zoom_set_value, id, value
  102.  
  103.   ON_ERROR, 2                        ;return to caller
  104.  
  105.   ; Retrieve the state
  106.   stash = WIDGET_INFO(id, /CHILD)
  107.   WIDGET_CONTROL, stash, GET_UVALUE=state, /NO_COPY
  108.  
  109.  
  110.   ; Put the value into the state structure
  111.   ;state.orig_image = byte(value)
  112.   ; Handle cases where set_value image is smaller or larger than orig_image
  113.   temp_size = size(value)
  114.   set_x_sz = temp_size[1]
  115.   set_y_sz = temp_size[2]
  116.   ; get the smaller section common to both orig_image and set_value
  117.   new_x_sz = state.x_im_sz < set_x_sz
  118.   new_y_sz = state.y_im_sz < set_y_sz
  119.   ; Set the state value.  Scale to range of the display here
  120.   ; so that display operations after this can simply use TV
  121.   ; and preserve the same range as in the original image
  122.   state.orig_image[0:new_x_sz-1,0:new_y_sz-1] = $
  123.      bytscl(value[0:new_x_sz-1,0:new_y_sz-1], top=!d.n_colors-1)
  124.  
  125.  
  126.   ; Get the window number from the draw widget.  This can only be done
  127.   ; after the widget has been realized.
  128.   WIDGET_CONTROL, state.draw, GET_VALUE=win_temp
  129.   state.draw_win = win_temp[0]
  130.   WIDGET_CONTROL, state.zoom, GET_VALUE=win_temp
  131.   state.zoom_win = win_temp[0]
  132.  
  133.   ; Use TV to display an image in the draw widget.  Set the window for
  134.   ; the TV command since there may be other draw windows.
  135.   ;Save window number
  136.   save_win = !D.WINDOW
  137.   WSET, state.draw_win
  138.   TV, state.orig_image
  139.   ;Restore window
  140.   WSET, save_win
  141.  
  142.   draw_zoom, state, state.oldx, state.oldy
  143.  
  144.   WIDGET_CONTROL, stash, SET_UVALUE=state, /NO_COPY
  145.  
  146. END
  147.  
  148. ;-----------------------------------------------------------------------------
  149.  
  150. FUNCTION zoom_get_value, id
  151.  
  152.   ON_ERROR, 2                                           ;return to caller
  153.  
  154.   ; Retrieve the state
  155.   stash = WIDGET_INFO(id, /CHILD)
  156.   WIDGET_CONTROL, stash, GET_UVALUE=state, /NO_COPY
  157.  
  158.   ; Get the value from the state structure
  159.   ret = state.zoom_image
  160.  
  161.   WIDGET_CONTROL, stash, SET_UVALUE=state, /NO_COPY
  162.   RETURN, ret
  163. END
  164.  
  165. ;-----------------------------------------------------------------------------
  166.  
  167. PRO draw_zoom, state, newx, newy
  168.  
  169.   ; compute size of rectangle in original image
  170.   ; round up to make sure image fills zoom window
  171.   rect_x = long(state.x_zm_sz / float(state.scale) + 0.999)
  172.   rect_y = long(state.y_zm_sz / float(state.scale) + 0.999)
  173.  
  174.   ; Plan to erase if the zoom rectangle is larger than the original
  175.   ;  image size.
  176.   doerase = (rect_x GT state.x_im_sz OR rect_y GT state.y_im_sz)
  177.  
  178.   rect_x = rect_x < state.x_im_sz
  179.   rect_y = rect_y < state.y_im_sz
  180.  
  181.   ; compute location of origin of rect (user specified center)
  182.   x0 = newx - rect_x/2
  183.   y0 = newy - rect_y/2
  184.  
  185.   ; make sure rectangle fits into original image
  186.   ;left edge from center
  187.   x0 = x0 > 0
  188.   ; limit right position
  189.   x0 = x0 < (state.x_im_sz - rect_x)
  190.  
  191.   ;bottom
  192.   y0 = y0 > 0
  193.   y0 = y0 < (state.y_im_sz - rect_y)
  194.  
  195.   ;Save window number
  196.   save_win = !D.WINDOW
  197.   WSET, state.zoom_win
  198.  
  199.   IF (state.scale EQ 1) THEN BEGIN
  200.     IF doerase THEN ERASE
  201.  
  202.     ; don't use tvscl here, to preserve same range as in unzoomed image
  203.     TV, state.orig_image[x0:x0+rect_x-1,y0:y0+rect_y-1]
  204.  
  205.   ENDIF ELSE BEGIN
  206.     ;Make integer rebin factors.  These may be larger than the zoom image
  207.     dim_x = rect_x * state.scale
  208.     dim_y = rect_y * state.scale
  209.  
  210.     ; Constrain upper right edge to within original image.
  211.     x1 = (x0 + rect_x - 1) < (state.x_im_sz-1)
  212.     y1 = (y0 + rect_y - 1) < (state.y_im_sz-1)
  213.  
  214.     temp_image = rebin(state.orig_image[x0:x1,y0:y1], $
  215.                        dim_x, dim_y, $
  216.                        sample=state.sample)
  217.  
  218.     ;Save the zoomed image
  219.     fill_x = dim_x < state.x_zm_sz 
  220.     fill_y = dim_y < state.y_zm_sz 
  221.     state.zoom_image[0:fill_x-1,0:fill_y-1] = temp_image[0:fill_x-1,0:fill_y-1]
  222.  
  223.     ; Pad with zoomed image with black if necessary.
  224.     if (fill_x LT state.x_zm_sz) then $
  225.       state.zoom_image[fill_x:state.x_zm_sz-1, *] = 0
  226.     if (fill_y LT state.y_zm_sz) then $
  227.       state.zoom_image[*, fill_y:state.y_zm_sz-1] = 0
  228.  
  229.     ;Save the corners in original image
  230.     state.x0 = x0
  231.     state.y0 = y0
  232.     state.x1 = x1
  233.     state.y1 = y1
  234.  
  235.     ;Display the new zoomed image
  236.     ;Save window number
  237.  
  238.     ; don't use tvscl here, to preserve same range as in unzoomed image
  239.     TV, state.zoom_image
  240.  
  241.  ENDELSE
  242.  
  243.  ;Restore window
  244.  WSET, save_win
  245. END
  246.  
  247.  
  248. ;-----------------------------------------------------------------------------
  249.  
  250. FUNCTION zoom_event, event
  251.  
  252.   ; Retrieve the structure from the child that contains the sub ids
  253.   parent=event.handler
  254.   stash = WIDGET_INFO(parent, /CHILD)
  255.   WIDGET_CONTROL, stash, GET_UVALUE=state, /NO_COPY
  256.  
  257.  
  258.   CASE event.id OF
  259.     state.draw: $
  260.        IF state.track GT 0 OR event.press EQ 1 THEN BEGIN
  261.         IF !order EQ 0 THEN $
  262.           y = event.y $
  263.         ELSE BEGIN
  264.             geo = widget_info(event.id, /GEOMETRY)
  265.             y = geo.draw_ysize - event.y
  266.         ENDELSE
  267.           draw_zoom, state, event.x, y
  268.           state.oldx = event.x
  269.           state.oldy = y
  270.        ENDIF
  271.  
  272.     state.slide: $
  273.        BEGIN
  274.           WIDGET_CONTROL, event.id, GET_VALUE = temp_scale
  275.           IF (temp_scale LT 1) THEN temp_scale = 1
  276.           state.scale = temp_scale
  277.           draw_zoom, state, state.oldx, state.oldy
  278.        END
  279.  
  280.     state.sample_base: $
  281.        CASE event.value OF
  282.           state.nn_id: BEGIN
  283.               state.sample = 1
  284.               draw_zoom, state, state.oldx, state.oldy
  285.                END
  286.           state.bilin_id: BEGIN
  287.                              state.sample = 0
  288.                              draw_zoom, state, state.oldx, state.oldy
  289.                       END
  290.        ENDCASE
  291.  
  292.     state.track_base: $
  293.        CASE event.value OF
  294.           state.notrack_id:  state.track = 0
  295.           state.track_id:    state.track = 1
  296.        ENDCASE
  297.     state.report_id: begin
  298.       ret = {ZOOM_EVENT, ID:parent, $
  299.         TOP:event.top, HANDLER:0L, $
  300.         x_zsize:state.x_zm_sz, y_zsize:state.y_zm_sz, $
  301.         x0:state.x0, y0:state.y0, $
  302.         x1:state.x1, y1:state.y1}
  303.       WIDGET_CONTROL, stash, SET_UVALUE=state, /NO_COPY
  304.       return, ret
  305.     end
  306. ENDCASE
  307.  
  308. ; Swallow events, except for the REPORT event
  309. WIDGET_CONTROL, stash, SET_UVALUE=state, /NO_COPY
  310. RETURN, 0
  311.  
  312. END
  313.  
  314. ;-----------------------------------------------------------------------------
  315.  
  316.  
  317. FUNCTION cw_zoom, parent, $
  318.         FRAME=frame, $
  319.         MAX=max, $
  320.         MIN=min, $
  321.         RETAIN=retain, $
  322.         SAMPLE=sample, $
  323.         SCALE=scale, $
  324.         TRACK=track, $
  325.         UVALUE = uval, $
  326.         XSIZE=xsize, $
  327.         YSIZE=ysize, $
  328.         X_SCROLL_SIZE=x_scroll_size, $
  329.         Y_SCROLL_SIZE=y_scroll_size, $
  330.         X_ZSIZE=x_zsize, $
  331.         Y_ZSIZE=y_zsize
  332.  
  333.   IF (N_PARAMS() NE 1) THEN MESSAGE, 'Incorrect number of arguments'
  334.  
  335.   ON_ERROR, 2                        ;return to caller
  336.  
  337.   ; Defaults for keywords
  338.   IF (N_ELEMENTS(frame) EQ 0) THEN frame = 0L
  339.   IF (N_ELEMENTS(max) EQ 0) THEN max = 20L
  340.   IF (N_ELEMENTS(min) EQ 0) THEN min = 1L
  341.   IF (N_ELEMENTS(retain) EQ 0) THEN retain = 1L
  342.   IF (N_ELEMENTS(sample) EQ 0) THEN sample = 0L
  343.   IF (N_ELEMENTS(scale) EQ 0) THEN scale = 4L
  344.   IF (N_ELEMENTS(track) EQ 0) THEN track = 0L
  345.   IF (N_ELEMENTS(uval) EQ 0)  THEN uval = 0L
  346.   IF (N_ELEMENTS(xsize) EQ 0) THEN xsize = 500L
  347.   IF (N_ELEMENTS(ysize) EQ 0) THEN ysize = 500L
  348.   IF (N_ELEMENTS(x_scroll_size) EQ 0) THEN x_scroll_size = 0L
  349.   IF (N_ELEMENTS(y_scroll_size) EQ 0) THEN y_scroll_size = 0L
  350.   IF (N_ELEMENTS(x_zsize) EQ 0) THEN x_zsize = 250L
  351.   IF (N_ELEMENTS(y_zsize) EQ 0) THEN y_zsize = 250L
  352.  
  353.   base = WIDGET_BASE(parent, $
  354.             EVENT_FUNC = 'zoom_event', $
  355.             FRAME = frame, $
  356.             FUNC_GET_VALUE='ZOOM_GET_VALUE', $
  357.             PRO_SET_VALUE='ZOOM_SET_VALUE', $
  358.             /ROW, $
  359.             UVALUE = uval)
  360.  
  361.   lcol = WIDGET_BASE(base, /COLUMN)
  362.  
  363.   ; A widget called 'draw' is created.
  364.   draw = WIDGET_DRAW(lcol, $
  365.     /BUTTON_EVENTS, $    ;generate events when buttons pressed
  366.     /MOTION_EVENTS, $
  367.     /FRAME, $
  368.     RETAIN = retain, $
  369.     XSIZE = xsize, $
  370.     YSIZE = ysize, $
  371.     X_SCROLL_SIZE = x_scroll_size, $
  372.     Y_SCROLL_SIZE = y_scroll_size)
  373.  
  374.   rcol = WIDGET_BASE(base, /COLUMN)
  375.  
  376.   ; The REPORT button:
  377.   report = WIDGET_BUTTON(rcol, $
  378.         VALUE = 'REPORT ZOOM TO PARENT')
  379.  
  380.   ; A label containing some instructions:
  381.   wdrlabel = WIDGET_LABEL(rcol, $
  382.        VALUE = 'Press left button to zoom.')
  383.  
  384.   ; A widget called 'zoom' is created.
  385.   zoom = WIDGET_DRAW(rcol, $
  386.         /FRAME, $
  387.         RETAIN = retain, $
  388.         XSIZE = x_zsize, $
  389.         YSIZE = y_zsize)
  390.  
  391.   IF (min LT 1) THEN min = 1
  392.   IF (max LT 1) THEN max = 1
  393.   slide = WIDGET_SLIDER(rcol, $
  394.                         MINIMUM = min, $
  395.                         MAXIMUM = max, $
  396.                         VALUE = scale, $
  397.                         TITLE = 'Zoom Scale', $
  398.                         /FRAME)
  399.  
  400.   ;make sure sample is 0 or 1
  401.   IF (sample GT 0) THEN sample = 1
  402.   sample_base = cw_bgroup(rcol, ['Bilinear', 'Nearest Neighbor'], $
  403.         /COLUMN, $
  404.         /EXCLUSIVE, $
  405.         /FRAME, $
  406.         IDS=sample_ids, $
  407.         LABEL_TOP = 'Interpolation Style', $
  408.         /NO_RELEASE, $
  409.         /RETURN_ID, $
  410.         SET_VALUE = sample)
  411.  
  412.   ;make sure track is 0 or 1
  413.   IF (track GT 0) THEN track = 1
  414.   track_base = cw_bgroup(rcol, ['Button Press Only', 'Track Cursor'], $
  415.         /COLUMN, $
  416.         /EXCLUSIVE, $
  417.         /FRAME, $
  418.         IDS=track_ids, $
  419.         LABEL_TOP = 'Cursor Input Style', $
  420.         /NO_RELEASE, $
  421.         /RETURN_ID, $
  422.         SET_VALUE = track)
  423.  
  424.   state = {    orig_image:    BYTARR(xsize,ysize), $
  425.         zoom_image:    BYTARR(x_zsize,y_zsize), $
  426.         draw:        draw, $
  427.         zoom:        zoom, $
  428.         slide:        slide, $
  429.         sample_base:    sample_base, $
  430.         bilin_id:    sample_ids[0], $
  431.         nn_id:        sample_ids[1], $
  432.         track_base:    track_base, $
  433.         notrack_id:    track_ids[0], $
  434.         track_id:    track_ids[1], $
  435.         report_id:    report, $
  436.         draw_win:    -1L, $
  437.         zoom_win:    -1L, $
  438.         x_im_sz:    xsize, $
  439.         y_im_sz:    ysize, $
  440.         retain:        1L, $
  441.         track:        track, $
  442.         scale:        scale, $
  443.         sample:        sample, $
  444.         x_zm_sz:    x_zsize, $
  445.         y_zm_sz:    y_zsize, $
  446.         oldx:        xsize / 2L, $
  447.         oldy:        ysize / 2L, $
  448.         x0:        0L, $
  449.         y0:        0L, $
  450.         x1:        0L, $
  451.         y1:        0L $
  452.         }
  453.  
  454.   WIDGET_CONTROL, WIDGET_INFO(base, /CHILD), SET_UVALUE=state, /NO_COPY
  455.   RETURN, base
  456.  
  457. END
  458.